home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / progutil / iostream.zoo / src / vsbscanf.cc < prev   
Encoding:
C/C++ Source or Header  |  1991-09-22  |  16.7 KB  |  725 lines

  1. /*
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. // Modified for GNU iostream by Per Bothner 1991.
  19.  
  20. #if defined(LIBC_SCCS) && !defined(lint)
  21. static char sccsid[] = "%W% (Berkeley) %G%";
  22. #endif /* LIBC_SCCS and not lint */
  23.  
  24. //#include <sys/stdc.h>
  25. #include <ioprivat.h>
  26. #include <ctype.h>
  27. #ifndef NO_STDARG
  28. #include <stdarg.h>
  29. #else
  30. #include <varargs.h>
  31. #endif
  32.  
  33. #ifndef    NO_FLOATING_POINT
  34. #define FLOATING_POINT
  35. #endif
  36.  
  37. #ifdef FLOATING_POINT
  38. #include "floatio.h"
  39. #define    BUF    (MAXEXP+MAXFRACT+3)    /* 3 = sign + decimal point + NUL */
  40. #else
  41. #define    BUF    40
  42. #endif
  43.  
  44. /*
  45.  * Flags used during conversion.
  46.  */
  47. #define    LONG        0x01    /* l: long or double */
  48. #define    LONGDBL        0x02    /* L: long double; unimplemented */
  49. #define    SHORT        0x04    /* h: short */
  50. #define    SUPPRESS    0x08    /* suppress assignment */
  51. #define    POINTER        0x10    /* weird %p pointer (`fake hex') */
  52. #define    NOSKIP        0x20    /* do not skip blanks */
  53.  
  54. /*
  55.  * The following are used in numeric conversions only:
  56.  * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
  57.  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
  58.  */
  59. #define    SIGNOK        0x40    /* +/- is (still) legal */
  60. #define    NDIGITS        0x80    /* no digits detected */
  61.  
  62. #define    DPTOK        0x100    /* (float) decimal point is still legal */
  63. #define    EXPOK        0x200    /* (float) exponent (e+3, etc) still legal */
  64.  
  65. #define    PFXOK        0x100    /* 0x prefix is (still) legal */
  66. #define    NZDIGITS    0x200    /* no zero digits detected */
  67.  
  68. /*
  69.  * Conversion types.
  70.  */
  71. #define    CT_CHAR        0    /* %c conversion */
  72. #define    CT_CCL        1    /* %[...] conversion */
  73. #define    CT_STRING    2    /* %s conversion */
  74. #define    CT_INT        3    /* integer, i.e., strtol or strtoul */
  75. #define    CT_FLOAT    4    /* floating, i.e., strtod */
  76.  
  77. #define u_char unsigned char
  78. #define u_long unsigned long
  79.  
  80. extern "C" u_long strtoul(const char*, char**, int);
  81. static u_char *__sccl(register char *tab, register u_char *fmt);
  82.  
  83. int __vsbscanf(register streambuf *stream, char const *fmt0, va_list ap)
  84. {
  85.     register u_char *fmt = (u_char *)fmt0;
  86.     register int c;        /* character from format, or conversion */
  87.     register size_t width;    /* field width, or 0 */
  88.     register char *p;    /* points into all kinds of strings */
  89.     register int n;        /* handy integer */
  90.     register int flags;    /* flags as defined above */
  91.     register char *p0;    /* saves original value of p when necessary */
  92.     int nassigned;        /* number of fields assigned */
  93.     int nread;        /* number of characters consumed from fp */
  94.     int base;        /* base argument to strtol/strtoul */
  95.     u_long (*ccfn)(const char*, char**, int);
  96.     // conversion function (strtol/strtoul)
  97.     char ccltab[256];    /* character class table for %[...] */
  98.     char buf[BUF];        /* buffer for numeric conversions */
  99.  
  100.     /* `basefix' is used to avoid `if' tests in the integer scanner */
  101.     static short basefix[17] =
  102.         { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
  103.  
  104.     nassigned = 0;
  105.     nread = 0;
  106.     for (;;) {
  107.         c = *fmt++;
  108.         if (c == 0)
  109.             return (nassigned);
  110.         if (isspace(c)) {
  111.             for (;;) {
  112.                     c = stream->sbumpc();
  113.                 if (c == EOF)
  114.                     return nassigned;
  115.                 if (!isspace(c)) {
  116.                     stream->sputbackc(c);
  117.                     break;
  118.                 }
  119.                 nread++;
  120.             }
  121.             continue;
  122.         }
  123.         if (c != '%')
  124.             goto literal;
  125.         width = 0;
  126.         flags = 0;
  127.         /*
  128.          * switch on the format.  continue if done;
  129.          * break once format type is derived.
  130.          */
  131. again:        c = *fmt++;
  132.         switch (c) {
  133.         case '%':
  134. literal:
  135.                 n = stream->sbumpc();
  136.             if (n == EOF)
  137.                 goto input_failure;
  138.             if (n != c) {
  139.                 stream->sputbackc(n);
  140.                 goto match_failure;
  141.             }
  142.             nread++;
  143.             continue;
  144.  
  145.         case '*':
  146.             flags |= SUPPRESS;
  147.             goto again;
  148.         case 'l':
  149.             flags |= LONG;
  150.             goto again;
  151.         case 'L':
  152.             flags |= LONGDBL;
  153.             goto again;
  154.         case 'h':
  155.             flags |= SHORT;
  156.             goto again;
  157.  
  158.         case '0': case '1': case '2': case '3': case '4':
  159.         case '5': case '6': case '7': case '8': case '9':
  160.             width = width * 10 + c - '0';
  161.             goto again;
  162.  
  163.         /*
  164.          * Conversions.
  165.          * Those marked `compat' are for 4.[123]BSD compatibility.
  166.          *
  167.          * (According to ANSI, E and X formats are supposed
  168.          * to the same as e and x.  Sorry about that.)
  169.          */
  170.         case 'D':    /* compat */
  171.             flags |= LONG;
  172.             /* FALLTHROUGH */
  173.         case 'd':
  174.             c = CT_INT;
  175.             ccfn = (u_long (*)())strtol;
  176.             base = 10;
  177.             break;
  178.  
  179.         case 'i':
  180.             c = CT_INT;
  181.             ccfn = (u_long (*)())strtol;
  182.             base = 0;
  183.             break;
  184.  
  185.         case 'O':    /* compat */
  186.             flags |= LONG;
  187.             /* FALLTHROUGH */
  188.         case 'o':
  189.             c = CT_INT;
  190.             ccfn = strtoul;
  191.             base = 8;
  192.             break;
  193.  
  194.         case 'u':
  195.             c = CT_INT;
  196.             ccfn = strtoul;
  197.             base = 10;
  198.             break;
  199.  
  200.         case 'X':    /* compat   XXX */
  201.             flags |= LONG;
  202.             /* FALLTHROUGH */
  203.         case 'x':
  204.             flags |= PFXOK;    /* enable 0x prefixing */
  205.             c = CT_INT;
  206.             ccfn = strtoul;
  207.             base = 16;
  208.             break;
  209.  
  210. #ifdef FLOATING_POINT
  211.         case 'E':    /* compat   XXX */
  212.         case 'F':    /* compat */
  213.             flags |= LONG;
  214.             /* FALLTHROUGH */
  215.         case 'e': case 'f': case 'g':
  216.             c = CT_FLOAT;
  217.             break;
  218. #endif
  219.  
  220.         case 's':
  221.             c = CT_STRING;
  222.             break;
  223.  
  224.         case '[':
  225.             fmt = __sccl(ccltab, fmt);
  226.             flags |= NOSKIP;
  227.             c = CT_CCL;
  228.             break;
  229.  
  230.         case 'c':
  231.             flags |= NOSKIP;
  232.             c = CT_CHAR;
  233.             break;
  234.  
  235.         case 'p':    /* pointer format is like hex */
  236.             flags |= POINTER | PFXOK;
  237.             c = CT_INT;
  238.             ccfn = strtoul;
  239.             base = 16;
  240.             break;
  241.  
  242.         case 'n':
  243.             if (flags & SUPPRESS)    /* ??? */
  244.                 continue;
  245.             if (flags & SHORT)
  246.                 *va_arg(ap, short *) = nread;
  247.             else if (flags & LONG)
  248.                 *va_arg(ap, long *) = nread;
  249.             else
  250.                 *va_arg(ap, int *) = nread;
  251.             continue;
  252.  
  253.         /*
  254.          * Disgusting backwards compatibility hacks.    XXX
  255.          */
  256.         case '\0':    /* compat */
  257.             return (EOF);
  258.  
  259.         default:    /* compat */
  260.             if (isupper(c))
  261.                 flags |= LONG;
  262.             c = CT_INT;
  263.             ccfn = (u_long (*)())strtol;
  264.             base = 10;
  265.             break;
  266.         }
  267.  
  268.         /*
  269.          * We have a conversion that requires input.
  270.          */
  271.         if (stream->sgetc() == EOF)
  272.             goto input_failure;
  273.  
  274.         /*
  275.          * Consume leading white space, except for formats
  276.          * that suppress this.
  277.          */
  278.         if ((flags & NOSKIP) == 0) {
  279.             n = *stream->_gptr;
  280.             while (isspace(n)) {
  281.             stream->_gptr++;
  282.             nread++;
  283.             n = stream->sgetc();
  284.             if (n == EOF)
  285.                 goto input_failure;
  286.             }
  287.             // Note that there is at least one character in
  288.             // the buffer, so conversions that do not set NOSKIP
  289.             // can no longer result in an input failure.
  290.         }
  291.  
  292.         /*
  293.          * Do the conversion.
  294.          */
  295.         switch (c) {
  296.  
  297.         case CT_CHAR:
  298.             /* scan arbitrary characters (sets NOSKIP) */
  299.             if (width == 0)
  300.                 width = 1;
  301.             if (flags & SUPPRESS) {
  302.                 size_t sum = 0;
  303.                 for (;;) {
  304.                 if ((n = stream->_egptr - stream->_gptr) < width) {
  305.                     sum += n;
  306.                     width -= n;
  307.                     stream->_gptr += n;
  308.                     if (stream->underflow() == EOF)
  309.                     if (sum == 0)
  310.                         goto input_failure;
  311.                     else
  312.                         break;
  313.                 } else {
  314.                     sum += width;
  315.                     stream->_gptr += width;
  316.                     break;
  317.                 }
  318.                 }
  319.                 nread += sum;
  320.             } else {
  321.                 size_t r = stream->sgetn((void *)va_arg(ap, char *),
  322.                          width);
  323.                 if (r == 0)
  324.                 goto input_failure;
  325.                 nread += r;
  326.                 nassigned++;
  327.             }
  328.             break;
  329.  
  330.         case CT_CCL:
  331.             /* scan a (nonempty) character class (sets NOSKIP) */
  332.             if (width == 0)
  333.                 width = ~0;    /* `infinity' */
  334.             /* take only those things in the class */
  335.             if (flags & SUPPRESS) {
  336.                 n = 0;
  337.                 while (ccltab[*stream->_gptr]) {
  338.                     n++, stream->_gptr++;
  339.                     if (--width == 0)
  340.                     break;
  341.                     if (stream->sgetc() == EOF) {
  342.                     if (n == 0)
  343.                         goto input_failure;
  344.                     break;
  345.                     }
  346.                 }
  347.                 if (n == 0)
  348.                     goto match_failure;
  349.             } else {
  350.                 p0 = p = va_arg(ap, char *);
  351.                 while (ccltab[*stream->_gptr]) {
  352.                 *p++ = *stream->_gptr++;
  353.                 if (--width == 0)
  354.                     break;
  355.                 if (stream->sgetc() == EOF)
  356.                     if (p == p0) {
  357.                     goto input_failure;
  358.                     break;
  359.                     }
  360.                 }
  361.                 n = p - p0;
  362.                 if (n == 0)
  363.                 goto match_failure;
  364.                 *p = 0;
  365.                 nassigned++;
  366.             }
  367.             nread += n;
  368.             break;
  369.  
  370.         case CT_STRING:
  371.             /* like CCL, but zero-length string OK, & no NOSKIP */
  372.             if (width == 0)
  373.                 width = ~0;
  374.             if (flags & SUPPRESS) {
  375.                 n = 0;
  376.                 while (!isspace(*stream->_gptr)) {
  377.                     n++, stream->_gptr++;
  378.                     if (--width == 0)
  379.                         break;
  380.                     if (stream->sgetc() == EOF)
  381.                         break;
  382.                 }
  383.                 nread += n;
  384.             } else {
  385.                 p0 = p = va_arg(ap, char *);
  386.                 while (!isspace(*stream->_gptr)) {
  387.                     *p++ = *stream->_gptr++;
  388.                     if (--width == 0)
  389.                         break;
  390.                     if (stream->sgetc() == EOF)
  391.                         break;
  392.                 }
  393.                 *p = 0;
  394.                 nread += p - p0;
  395.                 nassigned++;
  396.             }
  397.             continue;
  398.  
  399.         case CT_INT:
  400.             /* scan an integer as if by strtol/strtoul */
  401. #ifdef hardway
  402.             if (width == 0 || width > sizeof(buf) - 1)
  403.                 width = sizeof(buf) - 1;
  404. #else
  405.             /* size_t is unsigned, hence this optimisation */
  406.             if (--width > sizeof(buf) - 2)
  407.                 width = sizeof(buf) - 2;
  408.             width++;
  409. #endif
  410.             flags |= SIGNOK | NDIGITS | NZDIGITS;
  411.             for (p = buf; width; width--) {
  412.                 c = *stream->_gptr;
  413.                 /*
  414.                  * Switch on the character; `goto ok'
  415.                  * if we accept it as a part of number.
  416.                  */
  417.                 switch (c) {
  418.  
  419.                 /*
  420.                  * The digit 0 is always legal, but is
  421.                  * special.  For %i conversions, if no
  422.                  * digits (zero or nonzero) have been
  423.                  * scanned (only signs), we will have
  424.                  * base==0.  In that case, we should set
  425.                  * it to 8 and enable 0x prefixing.
  426.                  * Also, if we have not scanned zero digits
  427.                  * before this, do not turn off prefixing
  428.                  * (someone else will turn it off if we
  429.                  * have scanned any nonzero digits).
  430.                  */
  431.                 case '0':
  432.                     if (base == 0) {
  433.                         base = 8;
  434.                         flags |= PFXOK;
  435.                     }
  436.                     if (flags & NZDIGITS)
  437.                         flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
  438.                     else
  439.                         flags &= ~(SIGNOK|PFXOK|NDIGITS);
  440.                     goto ok;
  441.  
  442.                 /* 1 through 7 always legal */
  443.                 case '1': case '2': case '3':
  444.                 case '4': case '5': case '6': case '7':
  445.                     base = basefix[base];
  446.                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
  447.                     goto ok;
  448.  
  449.                 /* digits 8 and 9 ok iff decimal or hex */
  450.                 case '8': case '9':
  451.                     base = basefix[base];
  452.                     if (base <= 8)
  453.                         break;    /* not legal here */
  454.                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
  455.                     goto ok;
  456.  
  457.                 /* letters ok iff hex */
  458.                 case 'A': case 'B': case 'C':
  459.                 case 'D': case 'E': case 'F':
  460.                 case 'a': case 'b': case 'c':
  461.                 case 'd': case 'e': case 'f':
  462.                     /* no need to fix base here */
  463.                     if (base <= 10)
  464.                         break;    /* not legal here */
  465.                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
  466.                     goto ok;
  467.  
  468.                 /* sign ok only as first character */
  469.                 case '+': case '-':
  470.                     if (flags & SIGNOK) {
  471.                         flags &= ~SIGNOK;
  472.                         goto ok;
  473.                     }
  474.                     break;
  475.  
  476.                 /* x ok iff flag still set & 2nd char */
  477.                 case 'x': case 'X':
  478.                     if (flags & PFXOK && p == buf + 1) {
  479.                         base = 16;    /* if %i */
  480.                         flags &= ~PFXOK;
  481.                         goto ok;
  482.                     }
  483.                     break;
  484.                 }
  485.  
  486.                 /*
  487.                  * If we got here, c is not a legal character
  488.                  * for a number.  Stop accumulating digits.
  489.                  */
  490.                 break;
  491.         ok:
  492.                 /*
  493.                  * c is legal: store it and look at the next.
  494.                  */
  495.                 stream->_gptr++;
  496.                 if (stream->sgetc() == EOF)
  497.                     break;        /* EOF */
  498.             }
  499.             /*
  500.              * If we had only a sign, it is no good; push
  501.              * back the sign.  If the number ends in `x',
  502.              * it was [sign] '0' 'x', so push back the x
  503.              * and treat it as [sign] '0'.
  504.              */
  505.             if (flags & NDIGITS) {
  506.                 if (p > buf)
  507.                     (void) stream->sputbackc(*(u_char *)--p);
  508.                 goto match_failure;
  509.             }
  510.             c = ((u_char *)p)[-1];
  511.             if (c == 'x' || c == 'X') {
  512.                 --p;
  513.                 (void) stream->sputbackc(c);
  514.             }
  515.             if ((flags & SUPPRESS) == 0) {
  516.                 u_long res;
  517.  
  518.                 *p = 0;
  519.                 res = (*ccfn)(buf, (char **)NULL, base);
  520.                 if (flags & POINTER)
  521.                     *va_arg(ap, void **) = (void *)res;
  522.                 else if (flags & SHORT)
  523.                     *va_arg(ap, short *) = res;
  524.                 else if (flags & LONG)
  525.                     *va_arg(ap, long *) = res;
  526.                 else
  527.                     *va_arg(ap, int *) = res;
  528.                 nassigned++;
  529.             }
  530.             nread += p - buf;
  531.             break;
  532.  
  533. #ifdef FLOATING_POINT
  534.         case CT_FLOAT:
  535.             /* scan a floating point number as if by strtod */
  536. #ifdef hardway
  537.             if (width == 0 || width > sizeof(buf) - 1)
  538.                 width = sizeof(buf) - 1;
  539. #else
  540.             /* size_t is unsigned, hence this optimisation */
  541.             if (--width > sizeof(buf) - 2)
  542.                 width = sizeof(buf) - 2;
  543.             width++;
  544. #endif
  545.             flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
  546.             for (p = buf; width; width--) {
  547.                 c = *stream->_gptr;
  548.                 /*
  549.                  * This code mimicks the integer conversion
  550.                  * code, but is much simpler.
  551.                  */
  552.                 switch (c) {
  553.  
  554.                 case '0': case '1': case '2': case '3':
  555.                 case '4': case '5': case '6': case '7':
  556.                 case '8': case '9':
  557.                     flags &= ~(SIGNOK | NDIGITS);
  558.                     goto fok;
  559.  
  560.                 case '+': case '-':
  561.                     if (flags & SIGNOK) {
  562.                         flags &= ~SIGNOK;
  563.                         goto fok;
  564.                     }
  565.                     break;
  566.                 case '.':
  567.                     if (flags & DPTOK) {
  568.                         flags &= ~(SIGNOK | DPTOK);
  569.                         goto fok;
  570.                     }
  571.                     break;
  572.                 case 'e': case 'E':
  573.                     /* no exponent without some digits */
  574.                     if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
  575.                         flags =
  576.                             (flags & ~(EXPOK|DPTOK)) |
  577.                             SIGNOK | NDIGITS;
  578.                         goto fok;
  579.                     }
  580.                     break;
  581.                 }
  582.                 break;
  583.         fok:
  584.                 *p++ = c;
  585.                 stream->_gptr++;
  586.                 if (stream->sgetc() == EOF)
  587.                     break;    /* EOF */
  588.             }
  589.             /*
  590.              * If no digits, might be missing exponent digits
  591.              * (just give back the exponent) or might be missing
  592.              * regular digits, but had sign and/or decimal point.
  593.              */
  594.             if (flags & NDIGITS) {
  595.                 if (flags & EXPOK) {
  596.                     /* no digits at all */
  597.                     while (p > buf)
  598.                         stream->sputbackc(*(u_char *)--p);
  599.                     goto match_failure;
  600.                 }
  601.                 /* just a bad exponent (e and maybe sign) */
  602.                 c = *(u_char *)--p;
  603.                 if (c != 'e' && c != 'E') {
  604.                     (void)stream->sputbackc(c);/* sign */
  605.                     c = *(u_char *)--p;
  606.                 }
  607.                 (void) stream->sputbackc(c);
  608.             }
  609.             if ((flags & SUPPRESS) == 0) {
  610.                 double res;
  611.  
  612.                 *p = 0;
  613.                 res = atof(buf);
  614.                 if (flags & LONG)
  615.                     *va_arg(ap, double *) = res;
  616.                 else
  617.                     *va_arg(ap, float *) = res;
  618.                 nassigned++;
  619.             }
  620.             nread += p - buf;
  621.             break;
  622. #endif /* FLOATING_POINT */
  623.         }
  624.     }
  625. input_failure:
  626.     return (nassigned ? nassigned : -1);
  627. match_failure:
  628.     return (nassigned);
  629. }
  630.  
  631. /*
  632.  * Fill in the given table from the scanset at the given format
  633.  * (just after `[').  Return a pointer to the character past the
  634.  * closing `]'.  The table has a 1 wherever characters should be
  635.  * considered part of the scanset.
  636.  */
  637. static u_char *__sccl(register char *tab, register u_char *fmt)
  638. {
  639.     register int c, n, v;
  640.  
  641.     /* first `clear' the whole table */
  642.     c = *fmt++;        /* first char hat => negated scanset */
  643.     if (c == '^') {
  644.         v = 1;        /* default => accept */
  645.         c = *fmt++;    /* get new first char */
  646.     } else
  647.         v = 0;        /* default => reject */
  648.     /* should probably use memset here */
  649.     for (n = 0; n < 256; n++)
  650.         tab[n] = v;
  651.     if (c == 0)
  652.         return (fmt - 1);/* format ended before closing ] */
  653.  
  654.     /*
  655.      * Now set the entries corresponding to the actual scanset
  656.      * to the opposite of the above.
  657.      *
  658.      * The first character may be ']' (or '-') without being special;
  659.      * the last character may be '-'.
  660.      */
  661.     v = 1 - v;
  662.     for (;;) {
  663.         tab[c] = v;        /* take character c */
  664. doswitch:
  665.         n = *fmt++;        /* and examine the next */
  666.         switch (n) {
  667.  
  668.         case 0:            /* format ended too soon */
  669.             return (fmt - 1);
  670.  
  671.         case '-':
  672.             /*
  673.              * A scanset of the form
  674.              *    [01+-]
  675.              * is defined as `the digit 0, the digit 1,
  676.              * the character +, the character -', but
  677.              * the effect of a scanset such as
  678.              *    [a-zA-Z0-9]
  679.              * is implementation defined.  The V7 Unix
  680.              * scanf treats `a-z' as `the letters a through
  681.              * z', but treats `a-a' as `the letter a, the
  682.              * character -, and the letter a'.
  683.              *
  684.              * For compatibility, the `-' is not considerd
  685.              * to define a range if the character following
  686.              * it is either a close bracket (required by ANSI)
  687.              * or is not numerically greater than the character
  688.              * we just stored in the table (c).
  689.              */
  690.             n = *fmt;
  691.             if (n == ']' || n < c) {
  692.                 c = '-';
  693.                 break;    /* resume the for(;;) */
  694.             }
  695.             fmt++;
  696.             do {        /* fill in the range */
  697.                 tab[++c] = v;
  698.             } while (c < n);
  699. #if 1    /* XXX another disgusting compatibility hack */
  700.             /*
  701.              * Alas, the V7 Unix scanf also treats formats
  702.              * such as [a-c-e] as `the letters a through e'.
  703.              * This too is permitted by the standard....
  704.              */
  705.             goto doswitch;
  706. #else
  707.             c = *fmt++;
  708.             if (c == 0)
  709.                 return (fmt - 1);
  710.             if (c == ']')
  711.                 return (fmt);
  712. #endif
  713.             break;
  714.  
  715.         case ']':        /* end of scanset */
  716.             return (fmt);
  717.  
  718.         default:        /* just another character */
  719.             c = n;
  720.             break;
  721.         }
  722.     }
  723.     /* NOTREACHED */
  724. }
  725.